#pragma once
#include "Socket.hpp"

#include <iostream>
#include <memory>
#include <functional>
#include <pthread.h>

using func_t = std::function<std::string(std::string &, bool *error_code)>;

class TcpServer;

class ThreadData
{
public:
    ThreadData(TcpServer *tcp_this, Net_Work::Socket *sockp)
        : _this(tcp_this), _sockp(sockp)
    {
    }

public:
    TcpServer *_this;         //
    Net_Work::Socket *_sockp; // 套接字
};

class TcpServer
{
public:
    TcpServer(uint16_t port, func_t handler_request)
        : _port(port), _listensocket(new Net_Work::TcpSocket()), _handler_request(handler_request)
    {
        _listensocket->BuildListenSocketMethod(_port, Net_Work::backlog);
    }

    static void *ThreadRun(void *args)
    {
        // 分离线程
        pthread_detach(pthread_self());
        ThreadData *td = static_cast<ThreadData *>(args);
        // 读取报文
        std::string inbufferstream;
        while(true)
        {
            bool is_ok = true;
            if(!td->_sockp->Recv(&inbufferstream, 1024))
                break;
            // 读取到了客户端发送的报文
            // 执行回调，进行业务处理        
            std::string send_string = td->_this->_handler_request(inbufferstream, &is_ok); 
            if(is_ok)
            {
                // 发送相应报文
                // 处理完的结果就是已经封装好的报文
                if (!send_string.empty())
                {
                    td->_sockp->Send(send_string);
                }
            }
            else break;
        }

        // 释放资源
        td->_sockp->CloseSocket();
        delete td->_sockp;
        delete td;
        return nullptr;
    }

    void Loop()
    {
        while (true)
        {
            std::string peerip;
            uint16_t peerport;
            // 创建listen套接字
            Net_Work::Socket *newsock = _listensocket->AcceptConnection(&peerip, &peerport);
            if (newsock == nullptr)
                continue;
            std::cout << "获取一个新连接, sockfd: " << newsock->GetSockFd() << " client info: " << peerip << ":" << peerport << std::endl;

            // 多线程来执行任务
            pthread_t tid;
            ThreadData *td = new ThreadData(this, newsock);
            //
            pthread_create(&tid, nullptr, ThreadRun, td);
        }
    }

    ~TcpServer() {}

private:
    int _port;                       // 端口号
    Net_Work::Socket *_listensocket; // 监听套接字

public:
    func_t _handler_request; // 回调方法
};
